#pragma once

#include "behavior_analytics_server.h"
#include <chrono>
#include <iostream>
#include <iterator>
#include <log.h>
#include <memory>
#include <optional>
#include <string>
#include <sw/redis++/errors.h>
#include <sw/redis++/redis.h>
#include <unordered_set>
#include <utility>
#include <vector>


namespace lyt {
    class BehaviorAnalyticsRedis{
    private:
        std::shared_ptr<sw::redis::Redis> _client;
    public:
        using ptr = std::shared_ptr<BehaviorAnalyticsRedis>;
        BehaviorAnalyticsRedis(const std::shared_ptr<sw::redis::Redis> &client) : _client(client) {}
        // ==============================Code的缓存======================================
        bool SetBlogBehavior(const std::string &user_id, const std::string &blog_id,const int weight) {
            try {
                // 用来保存用户id和博客id的kv
                std::string list_key = "user:" + user_id + ":blog_id";
                // 用来保存每个记录的权重
                std::string hash_key = "user:" + user_id + ":weight";
                auto size = _client->llen(list_key);

                if(size < 10){
                    // 直接插入
                    _client->rpush(list_key,blog_id);
                    _client->hset(hash_key,blog_id,std::to_string(weight));
                    return true;
                }
                // >=10 进行淘汰，查找最早的权重最小的kv并且删除，取队首元素和权重
                std::vector<std::string> first_elem;
                // 从左往右取（队列）
                _client->lrange(list_key, 0, 0, std::back_inserter(first_elem));
                // 用来记录该删除的数据
                if(first_elem.empty()){
                    // 理论上不会为空
                    _client->rpush(list_key,blog_id);
                    _client->hset(hash_key,blog_id,std::to_string(weight));
                    return true;
                }
                std::string first_blog_id = first_elem[0];
                auto first_weight_str = _client->hget(hash_key,first_blog_id);
                int first_weight = std::stoi(*first_weight_str);
                if(weight == 1){
                    if(first_weight == 1){
                        // 直接淘汰，插入新数据
                        _client->lpop(list_key);
                        _client->hdel(hash_key,first_blog_id);

                        _client->rpush(list_key,blog_id);
                        _client->hset(hash_key,blog_id,"1");
                    }else{
                        // 将首元素权重-1
                        _client->hset(hash_key,first_blog_id,"1");
                        // 查找之后第一个权重为1的数据然后删除
                        // 查找后面第一个权重为1的元素
                        std::vector<std::string> rest;
                        _client->lrange(list_key, 1, -1, std::back_inserter(rest));

                        std::string to_remove;
                        for (const auto &pb_id : rest) {
                            auto w = _client->hget(hash_key, pb_id);
                            if (w && *w == "1") {
                                to_remove = pb_id;
                                break;
                            }
                        }

                        if (!to_remove.empty()) {
                            _client->lrem(list_key, 1, to_remove);
                            _client->hdel(hash_key, to_remove);

                            // 插入新数据
                            _client->rpush(list_key, blog_id);
                            _client->hset(hash_key, blog_id, "1");
                        }
                        // 找不到就不插入新数据，只减了队首权重
                    }
                }
                return true;
            } catch (const sw::redis::Error &err) {
                std::cerr << "SetRedisCode error: " << err.what() << std::endl;
                return false;
            }
        }
        std::pair<bool, std::vector<std::string>> GetBlogBehavior(const std::string &user_id) {
            std::vector<std::string> retvec;
            try {
                std::string list_key = "user:" + user_id + ":blog_id";
                // 从左往右取（队列）
                _client->lrange(list_key, 0, 0, std::back_inserter(retvec));
                return std::make_pair(true, retvec);
            } catch (const sw::redis::Error &err) {
                std::cerr << "DeleteCode error: " << err.what() << std::endl;
                return std::make_pair(false, retvec);
            }
        }
    private:
    };
    
} // namespace lyt